package com.inspectortime.webapp;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.axis.utils.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;

import com.inspectortime.domain.User;
import com.inspectortime.repository.Repository;
import com.inspectortime.util.SpringValidatorUtils;

/**
 * This controller takes two sets of input parameters: (1) A GET request with a
 * password reset token by itself. If this is a valid token then the
 * "enter new password" form is allowed to be displayed. (2) A POST form
 * submission containing a valid token and the new password, which will allow
 * the password reset to take place.
 * 
 * @author mKvalsvik
 * 
 */
public class ResetPasswordController extends SimpleFormController {

	private Repository repository;

	/**
	 * Treating every request (POST or GET) as a form submission ensures that
	 * validation of token will always occur.
	 */
	protected boolean isFormSubmission(HttpServletRequest request) {
		return true;
	}

	protected Object formBackingObject(HttpServletRequest request)
			throws Exception {
		PasswordResetForm form = new PasswordResetForm();
		return form;
	}

	protected void onBindAndValidate(HttpServletRequest request,
			Object command, BindException errors) throws Exception {
		PasswordResetForm form = (PasswordResetForm) command;
		this.validatePasswordResetToken(form, errors);
		
		// Don't validate password if token is invalid or password has not been entered
		if (errors.hasErrors()) {
			return;
		}
		
		// Verify the new password entered, if not then return. Note that this condition will have to be caught in onSubmit.
		if (StringUtils.isEmpty(form.getNewPassword())) {
			return;
		}
		SpringValidatorUtils.rejectInvalidPassword(errors, "newPassword");	
	}

	/**
	 * Validates that token format is right and exists in the database
	 * 
	 * @param form
	 * @param errors
	 */
	private void validatePasswordResetToken(PasswordResetForm form,
			BindException errors) {
		if (StringUtils.isEmpty(form.getResetCode())) {
			errors.rejectValue("resetCode", "required.resetCode");
			return;
		}
		if (form.getResetCode().length() != 20) {
			errors
					.rejectValue("resetCode", "invalid.resetCode");
			return;
		}
		User user = repository.findUserByPasswordResetToken(form
				.getResetCode());
		if (user == null) {
			errors.rejectValue("resetCode", "notFound.resetCode");
		}
	}

	protected ModelAndView onSubmit(HttpServletRequest request,
			HttpServletResponse response, Object command, BindException errors)
			throws Exception {

		PasswordResetForm form = (PasswordResetForm) command;
		User user = repository.findUserByPasswordResetToken(form
				.getResetCode());
		if (user == null) {
			throw new RuntimeException(
					"Should not happen, onBindAndValidate should have validated the token");
		}

		// Note we may get here even though no password has been entered.  Simply re-display form with no errors.
		if (StringUtils.isEmpty(form.getNewPassword())) {
			return new ModelAndView(getFormView(), errors.getModel());
		}		
		
		// Success
		user.setPasswordResetToken(null);
		//user.setPassword(form.getNewPassword());
		user.setCleartextPassword(form.getNewPassword());
		user.save();
		return new ModelAndView(getSuccessView());

	}

	public void setRepository(Repository repository) {
		this.repository = repository;
	}

}
